<template>
  <div class="roomlist">
    <header class="roomlist__header">
      <h3>现在，请选择一个游戏房间...</h3>
    </header>
    <TransitionListFade class="room-container">
      <Card
        v-for="room in roomlist"
        v-bind:key="room.id"
        class="room-card transition-list-fade-item"
        @click.native="handleClickRoom(room.id)"
      >
        {{ room.id }}
        <div class="room-card__wrapper">
          <Avatar :src="room.host.character.imgUrl">{{
            room.host.name[0]
          }}</Avatar>
          <dl class="info-list-dl">
            <dt>房间号</dt>
            <dd>{{ room.id }}</dd>
            <dt>人数</dt>
            <dd>{{ room.players.length }}</dd>
            <dt>难度</dt>
            <dd>{{ room.setting.difficulty | difficultyToStr }}</dd>
            <dt>房主</dt>
            <dd>{{ room.host.name }}</dd>
            <dt>模式</dt>
            <dd>{{ room.setting.mode | gameModeToStr }}</dd>
          </dl>
          <div :style="roomStatusStyle(room)">
            {{ room.status | roomStatusToStr }}
          </div>
        </div>
      </Card>
      <Card
        key="new-room"
        @click.native="handleClickAddNew"
        class="room-card room-added-card transition-list-fade-item"
      >
        <h3>创建新房间</h3>
        <Icon type="ios-add" />
      </Card>
    </TransitionListFade>
  </div>
</template>

<script lang="ts">
import { Component, Prop, Vue } from '@/plugins/class-component-hooks'
import {
  Room,
  RoomListSubscription,
  RoomsQuery,
  RoomListUpdatedKind,
  RoomStatus
} from '../types'
import {
  VueApolloComponentOptions,
  VueApolloQueryProperty,
  VueApolloQueryDefinition
} from 'vue-apollo/types/options'
import { Watch } from 'vue-property-decorator'
import { isThis } from '../types/Errors'
import { GraphQLError } from 'graphql'
import { gqlErrorHandler } from '../util/errorHandler'

enum Difficulty {
  easy = 'EASY',
  normal = 'Normal',
  hard = 'Hard'
}

interface INode {
  id: string
}

type RoomsType = RoomsQuery['rooms']
type RoomUnion = RoomListSubscription['roomListUpdated']['room']
type SRoom = Extract<RoomUnion, { __typename?: 'Room' }>
type SNode = Extract<RoomUnion, { __typename?: 'Node' }>

@Component
export default class RoomList extends Vue {
  private roomlist: RoomsType = []

  constructor() {
    super()
  }

  created() {}

  // @ts-ignore
  beforeRouteEnter(to, from, next) {
    next((vm: RoomList) => {
      vm.$apollo.queries.roomlist.refresh()
    })
  }

  roomStatusStyle(room: any) {
    let color: string
    if (room.status === RoomStatus.Gaming) {
      color = '#ff362f'
    } else {
      color = '#2dc515'
    }
    return {
      color
    }
  }

  async createRoom() {
    let res = await this.$apollo.mutate({
      mutation: require('@/graphql/createRoom.gql')
    })

    let data: Room = res.data.createRoom

    // push to router
    this.$router.push({
      path: `room/${data.id}`
    })
  }

  async joinRoom(roomID: string) {
    await this.$apollo.mutate({
      mutation: require('@/graphql/joinRoom.gql'),
      variables: {
        roomID
      }
    })

    this.$router.push({
      path: `room/${roomID}`
    })
  }

  handleClickAddNew() {
    this.createRoom().catch(err => {
      gqlErrorHandler(this, err)
    })
  }

  handleClickRoom(roomID: string) {
    this.joinRoom(roomID).catch(err => {
      gqlErrorHandler(this, err)
    })
  }

  get apollo(): Record<string, VueApolloQueryDefinition> {
    return {
      roomlist: {
        update: data => data.rooms,
        query: require('@/graphql/roomlist.gql'),
        variables(this: RoomList) {},
        subscribeToMore: [
          {
            document: require('@/graphql/subRoomList.gql'),
            updateQuery(this: RoomList, previous, { subscriptionData }) {
              let data: RoomListSubscription['roomListUpdated'] =
                subscriptionData.data.roomListUpdated
              let roomUnion: RoomUnion = data.room
              console.log(roomUnion)
              switch (data.kind) {
                case RoomListUpdatedKind.Added:
                case RoomListUpdatedKind.Updated: {
                  let room = roomUnion as SRoom
                  let idx = this.roomlist.findIndex(value => {
                    return value.id == room.id
                  })
                  if (idx == -1) {
                    // push
                    this.roomlist.push(room)
                  } else {
                    // update
                    this.roomlist.splice(idx, 1, room)
                  }
                  break
                }
                case RoomListUpdatedKind.Deleted: {
                  let node = roomUnion as SNode
                  let idx = this.roomlist.findIndex(value => {
                    return value.id == node.id
                  })
                  if (idx != -1) {
                    this.roomlist.splice(idx, 1)
                  }
                }
              }
            },
            onError(err: any) {
              gqlErrorHandler(this, err)
            }
          }
        ]
      }
    }
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
@import '@/styles/general.scss';

.roomlist__header {
  margin-bottom: 2rem;
}

.room-container {
  display: grid;
  grid-column-gap: 1.5rem;
  grid-row-gap: 2rem;

  @media screen and (min-width: $size-xsm) {
    grid-template-columns: 1fr 1fr;
  }

  @media screen and (min-width: $size-md) {
    grid-template-columns: 1fr 1fr 1fr;
  }

  @media screen and (min-width: $size-lg) {
    grid-template-columns: 1fr 1fr 1fr 1fr;
  }
}

.room-card {
  &__wrapper {
    display: flex;
    justify-content: space-around;

    > :nth-child(1) {
      margin-right: 1rem;
    }
    > :nth-child(2) {
      flex-grow: 1;
    }
  }
}

.room-added-card {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  border-style: dotted;

  h3 {
    text-align: center;
  }

  i.ivu-icon {
    font-size: 5rem;
  }
}
</style>
